/******************************************************************************* * Copyright (c) 2003, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Teddy Walker <teddy.walker@googlemail.com> * - Fix for Bug 151204 [Progress] Blocked status of jobs are not applied/reported *******************************************************************************/ package org.eclipse.ui.internal.progress; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IProgressMonitorWithBlocking; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.IJobManager; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.core.runtime.jobs.ProgressProvider; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.SingletonUtil; import org.eclipse.rap.ui.internal.progress.ProgressUtil; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.ImageLoader; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.internal.IPreferenceConstants; import org.eclipse.ui.internal.WorkbenchPlugin; import org.eclipse.ui.internal.dialogs.EventLoopProgressMonitor; import org.eclipse.ui.internal.dialogs.WorkbenchDialogBlockedHandler; import org.eclipse.ui.internal.misc.Policy; import org.eclipse.ui.progress.IProgressConstants; import org.eclipse.ui.progress.IProgressService; import org.eclipse.ui.progress.WorkbenchJob; import org.eclipse.ui.statushandlers.StatusAdapter; import org.eclipse.ui.statushandlers.StatusManager; import org.eclipse.ui.statushandlers.StatusManager.INotificationListener; import org.eclipse.ui.statushandlers.StatusManager.INotificationTypes; /** * JobProgressManager provides the progress monitor to the job manager and * informs any ProgressContentProviders of changes. */ public class ProgressManager extends ProgressProvider implements IProgressService { /** * A property to determine if the job was run in the dialog. Kept for * backwards compatability. * * @deprecated * @see IProgressConstants#PROPERTY_IN_DIALOG */ public static final QualifiedName PROPERTY_IN_DIALOG = IProgressConstants.PROPERTY_IN_DIALOG; private static final String ERROR_JOB = "errorstate.gif"; //$NON-NLS-1$ static final String ERROR_JOB_KEY = "ERROR_JOB"; //$NON-NLS-1$ // RAP [fappel]: ProgressManager needs to be session aware // private static ProgressManager singleton; Display display; public static class ProgressManagerProvider { public static ProgressManager getInstance() { ProgressManager instance = SingletonUtil.getSessionInstance( ProgressManager.class ); if( instance.display == null ) { Dialog.setBlockedHandler(new WorkbenchDialogBlockedHandler()); instance.display = Display.getCurrent(); // TODO [fappel]: find a better place for initialization... ProgressInfoItem.init(); URL iconsRoot = ProgressManagerUtil.getIconsRoot(); try { instance.setUpImage(iconsRoot, SLEEPING_JOB, SLEEPING_JOB_KEY); instance.setUpImage(iconsRoot, WAITING_JOB, WAITING_JOB_KEY); instance.setUpImage(iconsRoot, BLOCKED_JOB, BLOCKED_JOB_KEY); // Let the error manager set up its own icons ImageDescriptor errorImage = ImageDescriptor .createFromURL(new URL(iconsRoot, ERROR_JOB)); JFaceResources.getImageRegistry().put(ERROR_JOB_KEY, errorImage); } catch (MalformedURLException e) { ProgressManagerUtil.logException(e); } } return instance; } } final private Map jobs = Collections.synchronizedMap(new HashMap()); final private Map familyListeners = Collections .synchronizedMap(new HashMap()); // list of IJobProgressManagerListener private ListenerList listeners = new ListenerList(); // RAP [bm]: made public to access in org.eclipse.rap.ui.* public IJobChangeListener changeListener; static final String PROGRESS_VIEW_NAME = "org.eclipse.ui.views.ProgressView"; //$NON-NLS-1$ static final String PROGRESS_FOLDER = "$nl$/icons/full/progress/"; //$NON-NLS-1$ private static final String SLEEPING_JOB = "sleeping.gif"; //$NON-NLS-1$ private static final String WAITING_JOB = "waiting.gif"; //$NON-NLS-1$ private static final String BLOCKED_JOB = "lockedstate.gif"; //$NON-NLS-1$ /** * The key for the sleeping job icon. */ public static final String SLEEPING_JOB_KEY = "SLEEPING_JOB"; //$NON-NLS-1$ /** * The key for the waiting job icon. */ public static final String WAITING_JOB_KEY = "WAITING_JOB"; //$NON-NLS-1$ /** * The key for the locked job icon. */ public static final String BLOCKED_JOB_KEY = "LOCKED_JOB"; //$NON-NLS-1$ final Map runnableMonitors = Collections.synchronizedMap(new HashMap()); // A table that maps families to keys in the Jface image // table private Hashtable imageKeyTable = new Hashtable(); /* * A listener that allows for removing error jobs & indicators when errors * are handled. */ private final INotificationListener notificationListener; private static final String IMAGE_KEY = "org.eclipse.ui.progress.images"; //$NON-NLS-1$ /** * Get the progress manager currently in use. * * @return JobProgressManager */ public static ProgressManager getInstance() { // RAP [fappel]: ProgressManager needs to be session aware // if (singleton == null) { // singleton = new ProgressManager(); // } // return singleton; return ProgressManagerProvider.getInstance(); } /** * Shutdown the singleton if there is one. */ public static void shutdownProgressManager() { // RAP [fappel]: ProgressManager needs to be session aware // if (singleton == null) { // return; // } // singleton.shutdown(); if (getInstance() == null) { return; } getInstance().shutdown(); } /** * The JobMonitor is the inner class that handles the IProgressMonitor * integration with the ProgressMonitor. */ class JobMonitor implements IProgressMonitorWithBlocking { Job job; String currentTaskName; IProgressMonitorWithBlocking listener; /** * Create a monitor on the supplied job. * * @param newJob */ JobMonitor(Job newJob) { job = newJob; } /** * Add monitor as another monitor that * * @param monitor */ void addProgressListener(IProgressMonitorWithBlocking monitor) { listener = monitor; JobInfo info = getJobInfo(job); TaskInfo currentTask = info.getTaskInfo(); if (currentTask != null) { listener.beginTask(currentTaskName, currentTask.totalWork); listener.internalWorked(currentTask.preWork); } } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.IProgressMonitor#beginTask(java.lang.String, * int) */ public void beginTask(String taskName, int totalWork) { JobInfo info = getJobInfo(job); info.beginTask(taskName, totalWork); refreshJobInfo(info); currentTaskName = taskName; if (listener != null) { listener.beginTask(taskName, totalWork); } } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.IProgressMonitor#done() */ public void done() { final JobInfo info = getJobInfo(job); // RAP [if]: ensure mapping to context RWT.getUISession( display ).exec( new Runnable() { public void run() { info.clearTaskInfo(); } } ); info.clearChildren(); runnableMonitors.remove(job); if (listener != null) { listener.done(); } } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.IProgressMonitor#internalWorked(double) */ public void internalWorked(double work) { JobInfo info = getJobInfo(job); if (info.hasTaskInfo()) { info.addWork(work); refreshJobInfo(info); } if (listener != null) { listener.internalWorked(work); } } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.IProgressMonitor#isCanceled() */ public boolean isCanceled() { // Use the internal get so we don't create a Job Info for // a job that is not running (see bug 149857) JobInfo info = internalGetJobInfo(job); if (info == null) return false; return info.isCanceled(); } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.IProgressMonitor#setCanceled(boolean) */ public void setCanceled(boolean value) { JobInfo info = getJobInfo(job); // Don't bother cancelling twice if (value && !info.isCanceled()) { info.cancel(); // Only inform the first time if (listener != null) { listener.setCanceled(value); } } } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.IProgressMonitor#setTaskName(java.lang.String) */ public void setTaskName(String taskName) { JobInfo info = getJobInfo(job); if (info.hasTaskInfo()) { info.setTaskName(taskName); } else { beginTask(taskName, 100); return; } info.clearChildren(); refreshJobInfo(info); currentTaskName = taskName; if (listener != null) { listener.setTaskName(taskName); } } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.IProgressMonitor#subTask(java.lang.String) */ public void subTask(String name) { if (name == null) { return; } JobInfo info = getJobInfo(job); info.clearChildren(); info.addSubTask(name); refreshJobInfo(info); if (listener != null) { listener.subTask(name); } } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.IProgressMonitor#worked(int) */ public void worked(int work) { internalWorked(work); } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.IProgressMonitorWithBlocking#clearBlocked() */ public void clearBlocked() { JobInfo info = getJobInfo(job); info.setBlockedStatus(null); refreshJobInfo(info); if (listener != null) { listener.clearBlocked(); } } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.IProgressMonitorWithBlocking#setBlocked(org.eclipse.core.runtime.IStatus) */ public void setBlocked(IStatus reason) { JobInfo info = getJobInfo(job); info.setBlockedStatus(reason); refreshJobInfo(info); if (listener != null) { listener.setBlocked(reason); } } } /** * Create a new instance of the receiver. */ // RAP [bm]: made public to access in org.eclipse.rap.ui.* public ProgressManager() { // RAP [fappel]: // Job.getJobManager().setProgressProvider(this); // Dialog.setBlockedHandler(new WorkbenchDialogBlockedHandler()); createChangeListener(); notificationListener = createNotificationListener(); // RAP [fappel]: // Job.getJobManager().addJobChangeListener(this.changeListener); // URL iconsRoot = ProgressManagerUtil.getIconsRoot(); // try { // setUpImage(iconsRoot, SLEEPING_JOB, SLEEPING_JOB_KEY); // setUpImage(iconsRoot, WAITING_JOB, WAITING_JOB_KEY); // setUpImage(iconsRoot, BLOCKED_JOB, BLOCKED_JOB_KEY); // // // Let the error manager set up its own icons // setUpImages(iconsRoot); // } catch (MalformedURLException e) { // ProgressManagerUtil.logException(e); // } } private INotificationListener createNotificationListener() { return new StatusManager.INotificationListener(){ public void statusManagerNotified(int type, StatusAdapter[] adapters) { if(type == INotificationTypes.HANDLED){ FinishedJobs.getInstance().removeErrorJobs(); StatusAdapterHelper.getInstance().clear(); } } }; } /** * Create and return the IJobChangeListener registered with the Job manager. * * @return the created IJobChangeListener */ private void createChangeListener() { changeListener = new JobChangeAdapter() { /* * (non-Javadoc) * * @see org.eclipse.core.runtime.jobs.JobChangeAdapter#aboutToRun(org.eclipse.core.runtime.jobs.IJobChangeEvent) */ public void aboutToRun(IJobChangeEvent event) { JobInfo info = getJobInfo(event.getJob()); refreshJobInfo(info); Iterator startListeners = busyListenersForJob(event.getJob()) .iterator(); while (startListeners.hasNext()) { IJobBusyListener next = (IJobBusyListener) startListeners .next(); next.incrementBusy(event.getJob()); } } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.jobs.JobChangeAdapter#done(org.eclipse.core.runtime.jobs.IJobChangeEvent) */ public void done(IJobChangeEvent event) { // RAP [rh] run regardless of a running workbench (see bug 283595) // if (!PlatformUI.isWorkbenchRunning()) { // return; // } Iterator startListeners = busyListenersForJob(event.getJob()) .iterator(); while (startListeners.hasNext()) { IJobBusyListener next = (IJobBusyListener) startListeners .next(); next.decrementBusy(event.getJob()); } final JobInfo info = getJobInfo(event.getJob()); removeJobInfo(info); if (event.getResult() != null && event.getResult().getSeverity() == IStatus.ERROR) { StatusAdapter statusAdapter = new StatusAdapter(event .getResult()); statusAdapter.addAdapter(Job.class, event.getJob()); if (event .getJob() .getProperty( IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY) == Boolean.TRUE) { statusAdapter .setProperty( IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY, Boolean.TRUE); StatusAdapterHelper.getInstance().putStatusAdapter( info, statusAdapter); } StatusManager.getManager().handle(statusAdapter, StatusManager.SHOW); } } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.jobs.JobChangeAdapter#scheduled(org.eclipse.core.runtime.jobs.IJobChangeEvent) */ public void scheduled(IJobChangeEvent event) { updateFor(event); if (event.getJob().isUser()) { boolean noDialog = shouldRunInBackground(); if (!noDialog) { final IJobChangeEvent finalEvent = event; WorkbenchJob showJob = new WorkbenchJob( ProgressMessages.get().ProgressManager_showInDialogName) { /* * (non-Javadoc) * * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor) */ public IStatus runInUIThread( IProgressMonitor monitor) { showInDialog(null, finalEvent.getJob()); return Status.OK_STATUS; } }; showJob.setSystem(true); showJob.schedule(); return; } } } /** * Update the listeners for the receiver for the event. * * @param event */ private void updateFor(IJobChangeEvent event) { if (isInfrastructureJob(event.getJob())) { return; } if (jobs.containsKey(event.getJob())) { refreshJobInfo(getJobInfo(event.getJob())); } else { addJobInfo(new JobInfo(event.getJob())); } } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.jobs.JobChangeAdapter#awake(org.eclipse.core.runtime.jobs.IJobChangeEvent) */ public void awake(IJobChangeEvent event) { updateFor(event); } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.jobs.JobChangeAdapter#sleeping(org.eclipse.core.runtime.jobs.IJobChangeEvent) */ public void sleeping(IJobChangeEvent event) { if (jobs.containsKey(event.getJob()))// Are we showing this? sleepJobInfo(getJobInfo(event.getJob())); } }; } /** * The job in JobInfo is now sleeping. Refresh it if we are showing it, * remove it if not. * * @param info */ protected void sleepJobInfo(JobInfo info) { if (isInfrastructureJob(info.getJob())) return; GroupInfo group = info.getGroupInfo(); if (group != null) { sleepGroup(group,info); } Object[] listenersArray = listeners.getListeners(); for (int i = 0; i < listenersArray.length; i++) { IJobProgressManagerListener listener = (IJobProgressManagerListener) listenersArray[i]; // Is this one the user never sees? if (isNeverDisplaying(info.getJob(), listener.showsDebug())) continue; if (listener.showsDebug()) listener.refreshJobInfo(info); else listener.removeJob(info); } } /** * Refresh the group when info is sleeping. * @param group */ private void sleepGroup(GroupInfo group, JobInfo info) { Object[] listenersArray = listeners.getListeners(); for (int i = 0; i < listenersArray.length; i++) { IJobProgressManagerListener listener = (IJobProgressManagerListener) listenersArray[i]; if (isNeverDisplaying(info.getJob(), listener.showsDebug())) continue; if (listener.showsDebug() || group.isActive()) listener.refreshGroup(group); else listener.removeGroup(group); } } /** * Set up the image in the image regsitry. * * @param iconsRoot * @param fileName * @param key * @throws MalformedURLException */ private void setUpImage(URL iconsRoot, String fileName, String key) throws MalformedURLException { JFaceResources.getImageRegistry().put(key, ImageDescriptor.createFromURL(new URL(iconsRoot, fileName))); } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.jobs.ProgressProvider#createMonitor(org.eclipse.core.runtime.jobs.Job) */ public IProgressMonitor createMonitor(Job job) { return progressFor(job); } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.jobs.ProgressProvider#getDefaultMonitor() */ public IProgressMonitor getDefaultMonitor() { // only need a default monitor for operations the UI thread // and only if there is a display // RAP [fappel]: // Display display; // if (PlatformUI.isWorkbenchRunning() if (ProgressUtil.isWorkbenchRunning( display ) && !(PlatformUI.getWorkbench()).isStarting()) { // display = PlatformUI.getWorkbench().getDisplay(); if (!display.isDisposed() && (display.getThread() == Thread.currentThread())) { return new EventLoopProgressMonitor(new NullProgressMonitor()); } } return super.getDefaultMonitor(); } /** * Return a monitor for the job. Check if we cached a monitor for this job * previously for a long operation timeout check. * * @param job * @return IProgressMonitor */ public JobMonitor progressFor(Job job) { synchronized (runnableMonitors) { JobMonitor monitor = (JobMonitor) runnableMonitors.get(job); if (monitor == null) { monitor = new JobMonitor(job); runnableMonitors.put(job, monitor); } return monitor; } } /** * Add an IJobProgressManagerListener to listen to the changes. * * @param listener */ void addListener(IJobProgressManagerListener listener) { listeners.add(listener); } /** * Remove the supplied IJobProgressManagerListener from the list of * listeners. * * @param listener */ void removeListener(IJobProgressManagerListener listener) { listeners.remove(listener); } /** * Get the JobInfo for the job. If it does not exist create it. * * @param job * @return JobInfo */ JobInfo getJobInfo(Job job) { JobInfo info = internalGetJobInfo(job); if (info == null) { info = new JobInfo(job); jobs.put(job, info); } return info; } /** * Return an existing job info for the given Job or <code>null</code> if * there isn't one. * * @param job * @return JobInfo */ JobInfo internalGetJobInfo(Job job) { return (JobInfo) jobs.get(job); } /** * Refresh the IJobProgressManagerListeners as a result of a change in info. * * @param info */ public void refreshJobInfo(JobInfo info) { GroupInfo group = info.getGroupInfo(); if (group != null) { refreshGroup(group); } Object[] listenersArray = listeners.getListeners(); for (int i = 0; i < listenersArray.length; i++) { IJobProgressManagerListener listener = (IJobProgressManagerListener) listenersArray[i]; if (!isCurrentDisplaying(info.getJob(), listener.showsDebug())) { listener.refreshJobInfo(info); } } } /** * Refresh the IJobProgressManagerListeners as a result of a change in info. * * @param info */ public void refreshGroup(GroupInfo info) { Object[] listenersArray = listeners.getListeners(); for (int i = 0; i < listenersArray.length; i++) { ((IJobProgressManagerListener)listenersArray[i]).refreshGroup(info); } } /** * Refresh all the IJobProgressManagerListener as a result of a change in * the whole model. */ public void refreshAll() { pruneStaleJobs(); Object[] listenersArray = listeners.getListeners(); for (int i = 0; i < listenersArray.length; i++) { ((IJobProgressManagerListener)listenersArray[i]).refreshAll(); } } /** * Refresh the content providers as a result of a deletion of info. * * @param info * JobInfo */ public void removeJobInfo(JobInfo info) { Job job = info.getJob(); jobs.remove(job); runnableMonitors.remove(job); Object[] listenersArray = listeners.getListeners(); for (int i = 0; i < listenersArray.length; i++) { IJobProgressManagerListener listener = (IJobProgressManagerListener) listenersArray[i]; if (!isCurrentDisplaying(info.getJob(), listener.showsDebug())) { listener.removeJob(info); } } } /** * Remove the group from the roots and inform the listeners. * * @param group * GroupInfo */ public void removeGroup(GroupInfo group) { Object[] listenersArray = listeners.getListeners(); for (int i = 0; i < listenersArray.length; i++) { ((IJobProgressManagerListener)listenersArray[i]).removeGroup(group); } } /** * Refresh the content providers as a result of an addition of info. * * @param info */ public void addJobInfo(JobInfo info) { GroupInfo group = info.getGroupInfo(); if (group != null) { refreshGroup(group); } jobs.put(info.getJob(), info); Object[] listenersArray = listeners.getListeners(); for (int i = 0; i < listenersArray.length; i++) { IJobProgressManagerListener listener = (IJobProgressManagerListener) listenersArray[i]; if (!isCurrentDisplaying(info.getJob(), listener.showsDebug())) { listener.addJob(info); } } } /** * Return whether or not this job is currently displayable. * * @param job * @param debug * If the listener is in debug mode. * @return boolean <code>true</code> if the job is not displayed. */ boolean isCurrentDisplaying(Job job, boolean debug) { return isNeverDisplaying(job, debug) || job.getState() == Job.SLEEPING; } /** * Return whether or not we even display this job with debug mode set to * debug. * * @param job * @param debug * @return boolean */ boolean isNeverDisplaying(Job job, boolean debug) { if (isInfrastructureJob(job)) { return true; } if (debug) return false; return job.isSystem(); } /** * Return whether or not this job is an infrastructure job. * * @param job * @return boolean <code>true</code> if it is never displayed. */ private boolean isInfrastructureJob(Job job) { if (Policy.DEBUG_SHOW_ALL_JOBS) return false; return job.getProperty(ProgressManagerUtil.INFRASTRUCTURE_PROPERTY) != null; } /** * Return the current job infos filtered on debug mode. * * @param debug * @return JobInfo[] */ public JobInfo[] getJobInfos(boolean debug) { synchronized (jobs) { Iterator iterator = jobs.keySet().iterator(); Collection result = new ArrayList(); while (iterator.hasNext()) { Job next = (Job) iterator.next(); if (!isCurrentDisplaying(next, debug)) { result.add(jobs.get(next)); } } JobInfo[] infos = new JobInfo[result.size()]; result.toArray(infos); return infos; } } /** * Return the current root elements filtered on the debug mode. * * @param debug * @return JobTreeElement[] */ public JobTreeElement[] getRootElements(boolean debug) { synchronized (jobs) { Iterator iterator = jobs.keySet().iterator(); Collection result = new HashSet(); while (iterator.hasNext()) { Job next = (Job) iterator.next(); if (!isCurrentDisplaying(next, debug)) { JobInfo jobInfo = (JobInfo) jobs.get(next); GroupInfo group = jobInfo.getGroupInfo(); if (group == null) { result.add(jobInfo); } else { result.add(group); } } } JobTreeElement[] infos = new JobTreeElement[result.size()]; result.toArray(infos); return infos; } } /** * Return whether or not there are any jobs being displayed. * * @return boolean */ public boolean hasJobInfos() { synchronized (jobs) { Iterator iterator = jobs.keySet().iterator(); while (iterator.hasNext()) { return true; } return false; } } /** * Returns the image descriptor with the given relative path. * * @param source * @return Image */ Image getImage(ImageData source) { // RAP [rst]: constructing image with transparency mask not supported // ImageData mask = source.getTransparencyMask(); // return new Image(null, source, mask); return new Image( null, source ); } /** * Returns the image descriptor with the given relative path. * * @param fileSystemPath * The URL for the file system to the image. * @param loader - * the loader used to get this data * @return ImageData[] */ ImageData[] getImageData(URL fileSystemPath, ImageLoader loader) { try { InputStream stream = fileSystemPath.openStream(); ImageData[] result = loader.load(stream); stream.close(); return result; } catch (FileNotFoundException exception) { ProgressManagerUtil.logException(exception); return null; } catch (IOException exception) { ProgressManagerUtil.logException(exception); return null; } } /* * (non-Javadoc) * * @see org.eclipse.ui.progress.IProgressService#busyCursorWhile(org.eclipse.jface.operation.IRunnableWithProgress) */ public void busyCursorWhile(final IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException { final ProgressMonitorJobsDialog dialog = new ProgressMonitorJobsDialog( ProgressManagerUtil.getDefaultParent()); dialog.setOpenOnRun(false); final InvocationTargetException[] invokes = new InvocationTargetException[1]; final InterruptedException[] interrupt = new InterruptedException[1]; // show a busy cursor until the dialog opens Runnable dialogWaitRunnable = new Runnable() { public void run() { try { dialog.setOpenOnRun(false); setUserInterfaceActive(false); dialog.run(true, true, runnable); } catch (InvocationTargetException e) { invokes[0] = e; } catch (InterruptedException e) { interrupt[0] = e; } finally { setUserInterfaceActive(true); } } }; busyCursorWhile(dialogWaitRunnable, dialog); if (invokes[0] != null) { throw invokes[0]; } if (interrupt[0] != null) { throw interrupt[0]; } } /** * Show the busy cursor while the runnable is running. Schedule a job to * replace it with a progress dialog. * * @param dialogWaitRunnable * @param dialog */ private void busyCursorWhile(Runnable dialogWaitRunnable, ProgressMonitorJobsDialog dialog) { // create the job that will open the dialog after a delay scheduleProgressMonitorJob(dialog); final Display display = PlatformUI.getWorkbench().getDisplay(); if (display == null) { return; } // show a busy cursor until the dialog opens BusyIndicator.showWhile(display, dialogWaitRunnable); } /** * Schedule the job that will open the progress monitor dialog * * @param dialog * the dialog to open */ private void scheduleProgressMonitorJob( final ProgressMonitorJobsDialog dialog) { final WorkbenchJob updateJob = new WorkbenchJob( ProgressMessages.get().ProgressManager_openJobName) { /* * (non-Javadoc) * * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor) */ public IStatus runInUIThread(IProgressMonitor monitor) { setUserInterfaceActive(true); if (ProgressManagerUtil.safeToOpen(dialog, null)) { dialog.open(); } return Status.OK_STATUS; } }; updateJob.setSystem(true); updateJob.schedule(getLongOperationTime()); } /** * Shutdown the receiver. */ private void shutdown() { // RAP [fappel]: progress manager must not be shutdown since its not directly // added to jobmanager // synchronized (listenersKey) { // this.listeners = new IJobProgressManagerListener[0]; // } // Job.getJobManager().setProgressProvider(null); // Job.getJobManager().removeJobChangeListener(this.changeListener); } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.jobs.ProgressProvider#createProgressGroup() */ public IProgressMonitor createProgressGroup() { return new GroupInfo(); } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.jobs.ProgressProvider#createMonitor(org.eclipse.core.runtime.jobs.Job, * org.eclipse.core.runtime.IProgressMonitor, int) */ public IProgressMonitor createMonitor(Job job, IProgressMonitor group, int ticks) { JobMonitor monitor = progressFor(job); if (group instanceof GroupInfo) { GroupInfo groupInfo = (GroupInfo) group; JobInfo jobInfo = getJobInfo(job); jobInfo.setGroupInfo(groupInfo); jobInfo.setTicks(ticks); groupInfo.addJobInfo(jobInfo); } return monitor; } /** * Add the listener to the family. * * @param family * @param listener */ void addListenerToFamily(Object family, IJobBusyListener listener) { synchronized (familyListeners) { Collection currentListeners = (Collection) familyListeners.get(family); if (currentListeners == null) { currentListeners = new HashSet(); familyListeners.put(family, currentListeners); } currentListeners.add(listener); } } /** * Remove the listener from all families. * * @param listener */ void removeListener(IJobBusyListener listener) { synchronized (familyListeners) { Iterator families = familyListeners.keySet().iterator(); while (families.hasNext()) { Object next = families.next(); Collection currentListeners = (Collection) familyListeners .get(next); currentListeners.remove(listener); // Remove any empty listeners if (currentListeners.isEmpty()) { families.remove(); } } } } /** * Return the listeners for the job. * * @param job * @return Collection of IJobBusyListener */ private Collection busyListenersForJob(Job job) { if (job.isSystem()) { return Collections.EMPTY_LIST; } synchronized (familyListeners) { if (familyListeners.isEmpty()) { return Collections.EMPTY_LIST; } Iterator families = familyListeners.keySet().iterator(); Collection returnValue = new HashSet(); while (families.hasNext()) { Object next = families.next(); if (job.belongsTo(next)) { Collection currentListeners = (Collection) familyListeners .get(next); returnValue.addAll(currentListeners); } } return returnValue; } } /* * (non-Javadoc) * * @see org.eclipse.ui.progress.IProgressService#showInDialog(org.eclipse.swt.widgets.Shell, * org.eclipse.core.runtime.jobs.Job) */ public void showInDialog(Shell shell, Job job) { if (shouldRunInBackground()) { return; } final ProgressMonitorFocusJobDialog dialog = new ProgressMonitorFocusJobDialog( shell); dialog.show(job, shell); } /* * (non-Javadoc) * * @see org.eclipse.jface.operation.IRunnableContext#run(boolean, boolean, * org.eclipse.jface.operation.IRunnableWithProgress) */ public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException { if (fork == false || cancelable == false) { // backward compatible code final ProgressMonitorJobsDialog dialog = new ProgressMonitorJobsDialog( null); dialog.run(fork, cancelable, runnable); return; } busyCursorWhile(runnable); } /* * (non-Javadoc) * * @see org.eclipse.ui.progress.IProgressService#runInUI(org.eclipse.jface.operation.IRunnableWithProgress, * org.eclipse.core.runtime.jobs.ISchedulingRule) */ public void runInUI(final IRunnableContext context, final IRunnableWithProgress runnable, final ISchedulingRule rule) throws InvocationTargetException, InterruptedException { final RunnableWithStatus runnableWithStatus = new RunnableWithStatus( context, runnable, rule); final Display display = Display.getDefault(); display.syncExec(new Runnable() { public void run() { BusyIndicator.showWhile(display, runnableWithStatus); } }); IStatus status = runnableWithStatus.getStatus(); if (!status.isOK()) { Throwable exception = status.getException(); if (exception instanceof InvocationTargetException) throw (InvocationTargetException) exception; else if (exception instanceof InterruptedException) throw (InterruptedException) exception; else // should be OperationCanceledException throw new InterruptedException(exception.getMessage()); } } /* * (non-Javadoc) * * @see org.eclipse.ui.progress.IProgressService#getLongOperationTime() */ public int getLongOperationTime() { return 800; } /* * (non-Javadoc) * * @see org.eclipse.ui.progress.IProgressService#registerIconForFamily(org.eclipse.jface.resource.ImageDescriptor, * java.lang.Object) */ public void registerIconForFamily(ImageDescriptor icon, Object family) { String key = IMAGE_KEY + String.valueOf(imageKeyTable.size()); imageKeyTable.put(family, key); ImageRegistry registry = JFaceResources.getImageRegistry(); // Avoid registering twice if (registry.getDescriptor(key) == null) { registry.put(key, icon); } } /* * (non-Javadoc) * * @see org.eclipse.ui.progress.IProgressService#getIconFor(org.eclipse.core.runtime.jobs.Job) */ public Image getIconFor(Job job) { Enumeration families = imageKeyTable.keys(); while (families.hasMoreElements()) { Object next = families.nextElement(); if (job.belongsTo(next)) { return JFaceResources.getImageRegistry().get( (String) imageKeyTable.get(next)); } } return null; } /** * Iterate through all of the windows and set them to be disabled or enabled * as appropriate.' * * @param active * The set the windows will be set to. */ private void setUserInterfaceActive(boolean active) { IWorkbench workbench = PlatformUI.getWorkbench(); Shell[] shells = workbench.getDisplay().getShells(); if (active) { for (int i = 0; i < shells.length; i++) { if (!shells[i].isDisposed()) { shells[i].setEnabled(active); } } } else { // Deactive shells in reverse order for (int i = shells.length - 1; i >= 0; i--) { if (!shells[i].isDisposed()) { shells[i].setEnabled(active); } } } } /** * Check to see if there are any stale jobs we have not cleared out. * * @return <code>true</code> if anything was pruned */ private boolean pruneStaleJobs() { Object[] jobsToCheck = jobs.keySet().toArray(); boolean pruned = false; for (int i = 0; i < jobsToCheck.length; i++) { Job job = (Job) jobsToCheck[i]; if (checkForStaleness(job)) { if (Policy.DEBUG_STALE_JOBS) { WorkbenchPlugin.log("Stale Job " + job.getName()); //$NON-NLS-1$ } pruned = true; } } return pruned; } /** * Check the if the job should be removed from the list as it may be stale. * * @param job * @return boolean */ boolean checkForStaleness(Job job) { if (job.getState() == Job.NONE) { removeJobInfo(getJobInfo(job)); return true; } return false; } /** * Return whether or not dialogs should be run in the background * * @return <code>true</code> if the dialog should not be shown. */ private boolean shouldRunInBackground() { return WorkbenchPlugin.getDefault().getPreferenceStore().getBoolean( IPreferenceConstants.RUN_IN_BACKGROUND); } /** * Set whether or not the ProgressViewUpdater should show system jobs. * * @param showSystem */ public void setShowSystemJobs(boolean showSystem) { ProgressViewUpdater updater = ProgressViewUpdater.getSingleton(); updater.debug = showSystem; updater.refreshAll(); } private class RunnableWithStatus implements Runnable { IStatus status = Status.OK_STATUS; private final IRunnableContext context; private final IRunnableWithProgress runnable; private final ISchedulingRule rule; public RunnableWithStatus(IRunnableContext context, IRunnableWithProgress runnable, ISchedulingRule rule) { this.context = context; this.runnable = runnable; this.rule = rule; } public void run() { IJobManager manager = Job.getJobManager(); try { manager.beginRule(rule, getEventLoopMonitor()); context.run(false, false, runnable); } catch (InvocationTargetException e) { status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e .getMessage(), e); } catch (InterruptedException e) { status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e .getMessage(), e); } catch (OperationCanceledException e) { status = new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, e .getMessage(), e); } finally { manager.endRule(rule); } } /** * Get a progress monitor that forwards to an event loop monitor. * Override #setBlocked() so that we always open the blocked dialog. * * @return the monitor on the event loop */ private IProgressMonitor getEventLoopMonitor() { if (PlatformUI.getWorkbench().isStarting()) return new NullProgressMonitor(); return new EventLoopProgressMonitor(new NullProgressMonitor()) { public void setBlocked(IStatus reason) { // Set a shell to open with as we want to create // this // even if there is a modal shell. Dialog.getBlockedHandler().showBlocked( ProgressManagerUtil.getDefaultParent(), this, reason, getTaskName()); } }; } public IStatus getStatus() { return status; } } }